package com.newfiber.common.core.geometry;


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.operation.buffer.BufferOp;
import org.locationtech.jts.operation.buffer.BufferParameters;
import org.locationtech.jts.util.GeometricShapeFactory;

/**
 * @author : X.K
 * @since : 2023/3/4 下午5:02
 */
public class GeometryUtils {

	static PrecisionModel precisionModel = new PrecisionModel(PrecisionModel.FLOATING);

	static GeometryFactory geometryFactory = new GeometryFactory(precisionModel, 4326);

	static GeometricShapeFactory shapeFactory = new GeometricShapeFactory();

	static WKTReader reader = new WKTReader();

	public static Point createPoint(Object lon, Object lat){
		Coordinate coordinate = new Coordinate(Double.parseDouble(lon.toString()), Double.parseDouble(lat.toString()));
		return geometryFactory.createPoint( coordinate );
	}

	public static Polygon createCircle(double x, double y, final double radius){
		shapeFactory.setNumPoints(32);
		shapeFactory.setCentre(new Coordinate(x, y));
		shapeFactory.setSize(radius / (2 * Math.PI * 6371004) * 360);
		return shapeFactory.createCircle();
	}

	public static LineString createLineString(Coordinate[] coordinates){
		return geometryFactory.createLineString(coordinates);
	}

	public static LineString createLineString(List<Coordinate> coordinateList){
		return geometryFactory.createLineString(coordinateList.toArray(new Coordinate[coordinateList.size()]));
	}

	public static LineString createLineString(String linestringWkt){
		try {
			return (LineString) reader.read(linestringWkt);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Polygon createPolygon(String polygonWkt){
		try {
			return (Polygon) reader.read(polygonWkt);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Geometry bufferLineString(LineString lineString, Double leftBufferLength, Double rightBufferLength){
		BufferParameters bufferParameters = new BufferParameters();
		bufferParameters.setEndCapStyle(BufferParameters.CAP_FLAT);
		bufferParameters.setSingleSided(true);

		double leftBufferDistinct = leftBufferLength / (2 * Math.PI * 6371004) * 360;
		double rightBufferDistinct = rightBufferLength / (2 * Math.PI * 6371004) * 360;
		Geometry leftGeometry = BufferOp.bufferOp(lineString, leftBufferDistinct, bufferParameters);
		Geometry rightGeometry = BufferOp.bufferOp(lineString, rightBufferDistinct, bufferParameters);
		return leftGeometry.union(rightGeometry);
	}

	public static Geometry bufferLineString(LineString lineString, Double bufferLength){
		if(null == lineString){
			return null;
		}
		BufferOp bufOp = new BufferOp(lineString);
		bufOp.setEndCapStyle(BufferParameters.CAP_FLAT);
		double bufferDistinct = bufferLength / (2 * Math.PI * 6371004) * 360;
		return bufOp.getResultGeometry(bufferDistinct);
	}

	public static String parseLineStringWtkStr(List<Coordinate> coordinateList){
		if(CollectionUtils.isEmpty(coordinateList) || coordinateList.size() <= 1){
			return null;
		}
		String lineStringFormat = "LINESTRING(%s)";
		String pointValueFormat = "%s %s";
		List<String> lineStringValueList = coordinateList.stream().map(t -> String.format(pointValueFormat, t.getX(), t.getY())).collect(Collectors.toList());
		return String.format(lineStringFormat, String.join(",", lineStringValueList));
	}

	public static List<GeometryLngLat> parseLineStringLngLat(String lineStringWtkStr){
		if(StringUtils.isBlank(lineStringWtkStr)){
			return Collections.emptyList();
		}

		lineStringWtkStr = lineStringWtkStr.replace("LINESTRING", "").replace("(", "").replace(")", "");
		if(StringUtils.isBlank(lineStringWtkStr)){
			return Collections.emptyList();
		}

		List<GeometryLngLat> geometryLngLatList = new ArrayList<>();
		String[] lineStringWtkList = lineStringWtkStr.split(",");
		for(String lineStringWtk : lineStringWtkList){
			if(lineStringWtk.startsWith(" ")){
				lineStringWtk = lineStringWtk.substring(1);
			}
			String[] lineStringWtkArray = lineStringWtk.split(" ");
			geometryLngLatList.add(new GeometryLngLat(lineStringWtkArray[0], lineStringWtkArray[1]));
		}

		return geometryLngLatList;
	}

	/**
	 * 判断圆和线是否相交
	 *  1、求线的总长度 totalLength
	 *  2、求面和线的交线的总长度 mixedLength
	 *  3、totalLength > mixedLength 则相交
	 * @param polygon 面
	 * @param lineString 线
	 * @return 是否相交
	 */
	public static boolean judgeIntersection(Polygon polygon, LineString lineString){
		double totalLength = lineString.getLength();

		LineString intersection = (LineString) polygon.intersection(lineString);
		double mixedLength = intersection.getLength();

		return (totalLength > mixedLength) && mixedLength > 0;
	}
}
